/*
** gnl.c for libget_next_line in /home/guina_b/
** 
** Made by benoit guina
** Login   <guina_b@epitech.net>
** 
** Started on  Fri Jan 01 00:00:00 2010 benoit guina
** Last update Fri Jan 01 00:00:00 2010 benoit guina
*/

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "gnl_intern.h"

static int	nodes_apply(t_gnl_node *n,
			    int (*f)(t_gnl_node *, void *, void *),
			    void *p0, void *p1)
{
  t_gnl_node	*next;

  while (n)
    {
      next = n->n;
      if (!f(n, p0, p1))
	return (0);
      n = next;
    }
  return (1);
}

static t_gnl_node	*node_build(int fd, int *rread)
{
  t_gnl_node		*r;

  *rread = GNL_ERR_MALLOC;
  if ((r = malloc(sizeof(t_gnl_node))))
    {
      if ((*rread = read(fd, r->data, GNL_READSIZE)) > -1)
	{
	  r->n = 0;
	  r->data[*rread] = 0;
	  r->pos = 0;
	}
      else
	{
	  free(r);
	  r = 0;
	}
    }
  return (r);
}

static char		*nodes_to_str(t_gnl_node **nodes, int *err)
{
  char			*r;
  char			*r_end;
  int			l;
  t_gnl_node		*new_start;

  l = 0;
  nodes_apply(*nodes, _gnl_nodes_strlen, (void *)&l, 0);
  if ((r = malloc(l + 1)))
    {
      r_end = r;
      new_start = 0;
      nodes_apply(*nodes, _gnl_nodes_strcpy, (void *)&r_end, &new_start);
      *r_end = 0;
      nodes_apply(*nodes, _gnl_nodes_free, new_start, 0);
      *nodes = new_start;
    }
  else
    *err = GNL_ERR_MALLOC;
  return (r);
}

char			*get_next_line(int fd, int *err)
{
  static t_gnl_node	*nodes = 0;
  t_gnl_node		**cur;
  int			ret;

  *err = GNL_ERR_OK;
  ret = 0;
  nodes_apply(nodes, _gnl_nodes_strlen, 0, &ret);
  if (ret)
    return (nodes_to_str(&nodes, err));
  cur = &nodes;
  while (*cur)
    cur = &(*cur)->n;
  if (!(*cur = node_build(fd, &ret)) || (!ret && !nodes->data[nodes->pos]))
    {
      *err = (ret < 0) ? ret : GNL_ERR_OK;
      nodes_apply(nodes, _gnl_nodes_free, 0, 0);
      nodes = 0;
      return (0);
    }
  return (get_next_line(fd, err));
}
